Introducción a tidyverse

Jose M Sallan

MBA en Business Analytics

El tidyverse

https://tidyverse.org

https://tidyverse.org

Tidyverse básico

Visualizando con ggplot

Visualizando con ggplot

Manipulación de datos con dplyr

Manipulación de datos con dplyr

Tidyverse básico

Leyendo .csv con readr

Leyendo .csv con readr

Leyendo Excel con readxl

Leyendo Excel con readxl

Tidyverse básico

Transformación de tablas con tidyr

Transformación de tablas con tidyr

Comunicando resultados con rmarkdown

Comunicando resultados con rmarkdown

Referencias

Cargamos tidyverse haciendo:

library(tidyverse)

Visualizaciones con ggplot

Visualizaciones con ggplot

Visualizing with ggplot

Visualizing with ggplot

ggplot2 crea gráficos con la gramática de gráficos:

Los datos iris

Los famosos datos iris de Fisher o Anderson recogen las medidas en centímetros de la longitud (length) y anchura (width) de los sépalos (sepal) y pétalos (petal) de 50 flores de cada una de las tres especies de iris: setosa, versicolor and virginica.

head(iris)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa

Dos variables contínuas

¿Cómo podemos representar la relación entre Sepal.Length y Sepal.Width?

Creemos un gráfico de dispersión congeom_point():

ggplot(data = iris, mapping = aes(Sepal.Length, Sepal.Width)) +
  geom_point()

Añadiendo una línea de tendencia

Añadimos geom_smooth() para añadir una línea de tendencia.

ggplot(data = iris, mapping = aes(Sepal.Length, Sepal.Width)) +
  geom_point() +
  geom_smooth()
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

Variables categóricas

Podemos asignar un color a cada categoría (especie) haciendo color = Species en mapping:

ggplot(data = iris, mapping = aes(Sepal.Length, Sepal.Width, col = Species)) +
  geom_point()

color no define qué colores usamos, sino la información que transmitimos usando color.

Variables categóricas

Definamos una línea de regresión para cada categoría con geom_smooth(method = "lm")

ggplot(data = iris, mapping = aes(Sepal.Length, Sepal.Width, col = Species)) +
  geom_point() +
  geom_smooth(method = "lm")
## `geom_smooth()` using formula 'y ~ x'

Gráfico en facetas

En vez de usar color, podemos definir un gráfico en facetas.

ggplot(data = iris, mapping = aes(Sepal.Length, Sepal.Width)) +
  geom_point() +
  geom_smooth(method = "lm") +
  facet_grid(. ~ Species)
## `geom_smooth()` using formula 'y ~ x'

Variables continuas por categoría

¿Cómo se comporta Sepal.Length para cada Species?

Podemos usar un boxplot:

Boxplots para cada categoría

ggplot(data = iris, mapping = aes(Species, Sepal.Length)) +
  geom_boxplot(fill = c("#FF9933", "#6666FF", "#B2FF66"))

Más colores en: https://www.rapidtables.com/web/color/RGB_Color.html

Medidas de posición

ggplot(data = iris, mapping = aes(Species, Sepal.Length)) +
  stat_summary(fun.min = min, fun.max = max, fun = median)

Los datos mtcars

mtcars procede de la edición de 1974 de la revista Motor Trend US, e incluye consumo de combustible y diez aspectos de diseño y desempeño para 32 automóviles.

head(mtcars)
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1

Una Variable categóricas

¿Cuántos modelos tienen motores de cada uno de los valores de número de cilindros cyl?

Transformamos cyl de entera a categórica para hacer un gráfico de barras con geom_bar().

ggplot(mtcars, aes(factor(cyl))) +
  geom_bar()

Para crear el gráfico, geom_bar() cuenta el número de observaciones en cada categoría.

Dos variables categóricas

¿Cuántos modelos de cada número de cilindros tiene cambio automático o manual?

ggplot(mtcars, aes(factor(cyl), fill = factor(am))) +
  geom_bar()

Dos variables categóricas

¿Cuántos modelos de cada número de cilindros tiene cambio automático o manual?

ggplot(mtcars, aes(factor(cyl), fill = factor(am))) +
  geom_bar(position = "dodge")

Una variable contínua

Volvamos a iris: ¿Cuál es la distribución de Sepal.Length?

Podemos visualizarlas con histogramas o gráficos de densidad.

Histograma

Generamos histograma con geom_histogram(bins = 10). Hemos de especificar el número de barras con bins.

ggplot(data = iris, mapping = aes(Sepal.Length)) +
  geom_histogram(bins = 10)

Histograma

Refinando la estética:

ggplot(data = iris, mapping = aes(Sepal.Length)) +
  geom_histogram(bins = 10, fill = "#CCFFFF", color = "#808080")

fill y color no están en mapping, así que no estamos transmitiendo información adicional con el color.

Gráfico de densidad

Generamos gráficos de densidad con geom_density().

ggplot(data = iris, mapping = aes(Sepal.Length)) +
  geom_density()

Manipulación de datos con dplyr

Manipulación de datos con dplyr

Los verbos básicos de manipulación de datos:

Tablas con tibble

tibble es la versión de tidyverse del data frame.

iris <- tibble(iris)
iris
## # A tibble: 150 × 5
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
##           <dbl>       <dbl>        <dbl>       <dbl> <fct>  
##  1          5.1         3.5          1.4         0.2 setosa 
##  2          4.9         3            1.4         0.2 setosa 
##  3          4.7         3.2          1.3         0.2 setosa 
##  4          4.6         3.1          1.5         0.2 setosa 
##  5          5           3.6          1.4         0.2 setosa 
##  6          5.4         3.9          1.7         0.4 setosa 
##  7          4.6         3.4          1.4         0.3 setosa 
##  8          5           3.4          1.5         0.2 setosa 
##  9          4.4         2.9          1.4         0.2 setosa 
## 10          4.9         3.1          1.5         0.1 setosa 
## # … with 140 more rows

Filtrando por filas

filter(iris, Sepal.Length >= 7.5)
## # A tibble: 6 × 5
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species  
##          <dbl>       <dbl>        <dbl>       <dbl> <fct>    
## 1          7.6         3            6.6         2.1 virginica
## 2          7.7         3.8          6.7         2.2 virginica
## 3          7.7         2.6          6.9         2.3 virginica
## 4          7.7         2.8          6.7         2   virginica
## 5          7.9         3.8          6.4         2   virginica
## 6          7.7         3            6.1         2.3 virginica

Filtrando por filas

filter(iris, Sepal.Length >= 6.5, Species == "versicolor")
## # A tibble: 9 × 5
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species   
##          <dbl>       <dbl>        <dbl>       <dbl> <fct>     
## 1          7           3.2          4.7         1.4 versicolor
## 2          6.9         3.1          4.9         1.5 versicolor
## 3          6.5         2.8          4.6         1.5 versicolor
## 4          6.6         2.9          4.6         1.3 versicolor
## 5          6.7         3.1          4.4         1.4 versicolor
## 6          6.6         3            4.4         1.4 versicolor
## 7          6.8         2.8          4.8         1.4 versicolor
## 8          6.7         3            5           1.7 versicolor
## 9          6.7         3.1          4.7         1.5 versicolor

Ordenando por valor

To arrange means ordering by a colum or columns

arrange(iris, Sepal.Length)
## # A tibble: 150 × 5
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
##           <dbl>       <dbl>        <dbl>       <dbl> <fct>  
##  1          4.3         3            1.1         0.1 setosa 
##  2          4.4         2.9          1.4         0.2 setosa 
##  3          4.4         3            1.3         0.2 setosa 
##  4          4.4         3.2          1.3         0.2 setosa 
##  5          4.5         2.3          1.3         0.3 setosa 
##  6          4.6         3.1          1.5         0.2 setosa 
##  7          4.6         3.4          1.4         0.3 setosa 
##  8          4.6         3.6          1           0.2 setosa 
##  9          4.6         3.2          1.4         0.2 setosa 
## 10          4.7         3.2          1.3         0.2 setosa 
## # … with 140 more rows

Ordenando por valor

Decreasing order:

arrange(iris, -Sepal.Length)
## # A tibble: 150 × 5
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species  
##           <dbl>       <dbl>        <dbl>       <dbl> <fct>    
##  1          7.9         3.8          6.4         2   virginica
##  2          7.7         3.8          6.7         2.2 virginica
##  3          7.7         2.6          6.9         2.3 virginica
##  4          7.7         2.8          6.7         2   virginica
##  5          7.7         3            6.1         2.3 virginica
##  6          7.6         3            6.6         2.1 virginica
##  7          7.4         2.8          6.1         1.9 virginica
##  8          7.3         2.9          6.3         1.8 virginica
##  9          7.2         3.6          6.1         2.5 virginica
## 10          7.2         3.2          6           1.8 virginica
## # … with 140 more rows

Ordenando por valor

By two variables

arrange(iris, Species, -Sepal.Length)
## # A tibble: 150 × 5
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
##           <dbl>       <dbl>        <dbl>       <dbl> <fct>  
##  1          5.8         4            1.2         0.2 setosa 
##  2          5.7         4.4          1.5         0.4 setosa 
##  3          5.7         3.8          1.7         0.3 setosa 
##  4          5.5         4.2          1.4         0.2 setosa 
##  5          5.5         3.5          1.3         0.2 setosa 
##  6          5.4         3.9          1.7         0.4 setosa 
##  7          5.4         3.7          1.5         0.2 setosa 
##  8          5.4         3.9          1.3         0.4 setosa 
##  9          5.4         3.4          1.7         0.2 setosa 
## 10          5.4         3.4          1.5         0.4 setosa 
## # … with 140 more rows

Seleccionando columnas

select(iris, Sepal.Length, Sepal.Width)
## # A tibble: 150 × 2
##    Sepal.Length Sepal.Width
##           <dbl>       <dbl>
##  1          5.1         3.5
##  2          4.9         3  
##  3          4.7         3.2
##  4          4.6         3.1
##  5          5           3.6
##  6          5.4         3.9
##  7          4.6         3.4
##  8          5           3.4
##  9          4.4         2.9
## 10          4.9         3.1
## # … with 140 more rows

Seleccionando columnas

select(iris, -Species)
## # A tibble: 150 × 4
##    Sepal.Length Sepal.Width Petal.Length Petal.Width
##           <dbl>       <dbl>        <dbl>       <dbl>
##  1          5.1         3.5          1.4         0.2
##  2          4.9         3            1.4         0.2
##  3          4.7         3.2          1.3         0.2
##  4          4.6         3.1          1.5         0.2
##  5          5           3.6          1.4         0.2
##  6          5.4         3.9          1.7         0.4
##  7          4.6         3.4          1.4         0.3
##  8          5           3.4          1.5         0.2
##  9          4.4         2.9          1.4         0.2
## 10          4.9         3.1          1.5         0.1
## # … with 140 more rows

Seleccionando columnas

Usando tidyselect:

select(iris, ends_with("Length"))
## # A tibble: 150 × 2
##    Sepal.Length Petal.Length
##           <dbl>        <dbl>
##  1          5.1          1.4
##  2          4.9          1.4
##  3          4.7          1.3
##  4          4.6          1.5
##  5          5            1.4
##  6          5.4          1.7
##  7          4.6          1.4
##  8          5            1.5
##  9          4.4          1.4
## 10          4.9          1.5
## # … with 140 more rows

Combinando verbos

Para combinar verbos necesitaríamos variables auxiliares…

aux <- filter(iris,  Sepal.Length >= 6.5, Species == "versicolor")
select(aux, -Species)
## # A tibble: 9 × 4
##   Sepal.Length Sepal.Width Petal.Length Petal.Width
##          <dbl>       <dbl>        <dbl>       <dbl>
## 1          7           3.2          4.7         1.4
## 2          6.9         3.1          4.9         1.5
## 3          6.5         2.8          4.6         1.5
## 4          6.6         2.9          4.6         1.3
## 5          6.7         3.1          4.4         1.4
## 6          6.6         3            4.4         1.4
## 7          6.8         2.8          4.8         1.4
## 8          6.7         3            5           1.7
## 9          6.7         3.1          4.7         1.5

Combinando verbos con piping

…pero en vez de eso podemos usar el operador de piping%>%

iris %>%
  filter(Sepal.Length >= 6.5, Species == "versicolor") %>%
  select(-Species)
## # A tibble: 9 × 4
##   Sepal.Length Sepal.Width Petal.Length Petal.Width
##          <dbl>       <dbl>        <dbl>       <dbl>
## 1          7           3.2          4.7         1.4
## 2          6.9         3.1          4.9         1.5
## 3          6.5         2.8          4.6         1.5
## 4          6.6         2.9          4.6         1.3
## 5          6.7         3.1          4.4         1.4
## 6          6.6         3            4.4         1.4
## 7          6.8         2.8          4.8         1.4
## 8          6.7         3            5           1.7
## 9          6.7         3.1          4.7         1.5

Creando nuevas variables

Creamos iris_b a partir de iris:

iris_b <- iris %>%
  mutate(sepal = Sepal.Length*Sepal.Width) %>%
  select(-Petal.Length, -Petal.Width)
iris_b
## # A tibble: 150 × 4
##    Sepal.Length Sepal.Width Species sepal
##           <dbl>       <dbl> <fct>   <dbl>
##  1          5.1         3.5 setosa   17.8
##  2          4.9         3   setosa   14.7
##  3          4.7         3.2 setosa   15.0
##  4          4.6         3.1 setosa   14.3
##  5          5           3.6 setosa   18  
##  6          5.4         3.9 setosa   21.1
##  7          4.6         3.4 setosa   15.6
##  8          5           3.4 setosa   17  
##  9          4.4         2.9 setosa   12.8
## 10          4.9         3.1 setosa   15.2
## # … with 140 more rows

Renombrando variables

Renombramos variables haciendo rename(nuevo nombre = nombre actual)

iris_b <- iris_b %>%
  rename(sepal_length = Sepal.Length,
         sepal_width = Sepal.Width)

Obteniendo valores resumen

Podemos obteer la media mean de Sepal.Length y Sepal.Width:

iris %>%
  summarise(msl = mean(Sepal.Length),
            msw = mean(Sepal.Width))
## # A tibble: 1 × 2
##     msl   msw
##   <dbl> <dbl>
## 1  5.84  3.06

La tabla resultante tiene una sola fila.

Obteniendo valores resumen

Podemos obtener la media de todos los valores numéricos de iris con:

iris %>%
  summarise(across(where(is.numeric), mean))
## # A tibble: 1 × 4
##   Sepal.Length Sepal.Width Petal.Length Petal.Width
##          <dbl>       <dbl>        <dbl>       <dbl>
## 1         5.84        3.06         3.76        1.20

Valores resumen por grupos

Podemos obtener valores resumen para cada uno de los valores de una o varias variables categóricas con group_by.

Medias de las variables numéricas para cada valor de Species:

## # A tibble: 3 × 5
##   Species    Sepal.Length Sepal.Width Petal.Length Petal.Width
##   <fct>             <dbl>       <dbl>        <dbl>       <dbl>
## 1 setosa             5.01        3.43         1.46       0.246
## 2 versicolor         5.94        2.77         4.26       1.33 
## 3 virginica          6.59        2.97         5.55       2.03

Combinando manipulación de datos y visualización

iris %>%
  group_by(Species) %>%
  summarise(msl = mean(Sepal.Length)) %>%
  ggplot(aes(Species, msl)) +
  geom_bar(stat = "identity")

Usamos geom_bar con stat = "identity" porque la altura de las barras es proporcional al valor de la variable.

Manipulación de tablas con tidyr

Datos ordenados

tidyverse asume datos ordenados (tidy):

iris and mtcars are examples of tidy data.

Datos no ordenados

relig_income %>%
  head()
## # A tibble: 6 × 11
##   religion  `<$10k` `$10-20k` `$20-30k` `$30-40k` `$40-50k` `$50-75k` `$75-100k`
##   <chr>       <dbl>     <dbl>     <dbl>     <dbl>     <dbl>     <dbl>      <dbl>
## 1 Agnostic       27        34        60        81        76       137        122
## 2 Atheist        12        27        37        52        35        70         73
## 3 Buddhist       27        21        30        34        33        58         62
## 4 Catholic      418       617       732       670       638      1116        949
## 5 Don’t kn…      15        14        15        11        10        35         21
## 6 Evangeli…     575       869      1064       982       881      1486        949
## # … with 3 more variables: `$100-150k` <dbl>, `>150k` <dbl>,
## #   `Don't know/refused` <dbl>

El paquete tidyr

El paquetetidyr transforma tablas:

Los ordenadores entienden tablas largas, los humanos leemos bien tablas anchas.

De ancha a larga

relig_income %>%
  pivot_longer(-religion,
               names_to = "income",
               values_to = "count")
## # A tibble: 180 × 3
##    religion income             count
##    <chr>    <chr>              <dbl>
##  1 Agnostic <$10k                 27
##  2 Agnostic $10-20k               34
##  3 Agnostic $20-30k               60
##  4 Agnostic $30-40k               81
##  5 Agnostic $40-50k               76
##  6 Agnostic $50-75k              137
##  7 Agnostic $75-100k             122
##  8 Agnostic $100-150k            109
##  9 Agnostic >150k                 84
## 10 Agnostic Don't know/refused    96
## # … with 170 more rows

De larga a ancha

fish_encounters presenta información sobre peces nadando a lo largo de las estaciones de un río. Cada estación monitoriza de manera independiente si un determinado pez ha sido visto en la estación.

fish_encounters
## # A tibble: 114 × 3
##    fish  station  seen
##    <fct> <fct>   <int>
##  1 4842  Release     1
##  2 4842  I80_1       1
##  3 4842  Lisbon      1
##  4 4842  Rstr        1
##  5 4842  Base_TD     1
##  6 4842  BCE         1
##  7 4842  BCW         1
##  8 4842  BCE2        1
##  9 4842  BCW2        1
## 10 4842  MAE         1
## # … with 104 more rows

No todas las combinaciones de peces y estaciones están presentes en la tabla.

De larga a ancha

Usamos values_fill = list(seen = 0) para fijar igual a cero valores no presentes en la tabla larga.

fish_encounters %>%
  pivot_wider(values_from = "seen",
              names_from = "station",
              values_fill = list(seen = 0))
## # A tibble: 19 × 12
##    fish  Release I80_1 Lisbon  Rstr Base_TD   BCE   BCW  BCE2  BCW2   MAE   MAW
##    <fct>   <int> <int>  <int> <int>   <int> <int> <int> <int> <int> <int> <int>
##  1 4842        1     1      1     1       1     1     1     1     1     1     1
##  2 4843        1     1      1     1       1     1     1     1     1     1     1
##  3 4844        1     1      1     1       1     1     1     1     1     1     1
##  4 4845        1     1      1     1       1     0     0     0     0     0     0
##  5 4847        1     1      1     0       0     0     0     0     0     0     0
##  6 4848        1     1      1     1       0     0     0     0     0     0     0
##  7 4849        1     1      0     0       0     0     0     0     0     0     0
##  8 4850        1     1      0     1       1     1     1     0     0     0     0
##  9 4851        1     1      0     0       0     0     0     0     0     0     0
## 10 4854        1     1      0     0       0     0     0     0     0     0     0
## 11 4855        1     1      1     1       1     0     0     0     0     0     0
## 12 4857        1     1      1     1       1     1     1     1     1     0     0
## 13 4858        1     1      1     1       1     1     1     1     1     1     1
## 14 4859        1     1      1     1       1     0     0     0     0     0     0
## 15 4861        1     1      1     1       1     1     1     1     1     1     1
## 16 4862        1     1      1     1       1     1     1     1     1     0     0
## 17 4863        1     1      0     0       0     0     0     0     0     0     0
## 18 4864        1     1      0     0       0     0     0     0     0     0     0
## 19 4865        1     1      1     0       0     0     0     0     0     0     0

Leyendo archivos con readr y readxl

Leyendo archivos csv con readr

Funciones para leer archivos desde tidyverse.

lectura escritura archivos
read_delim write_delim delimitador genérico
read_table espacios en blanco
read_tsv write_tsv separados por tabulador
read_csv write_csv archivos .csv (EN)
read_csv2 write_csv2 archivos .csv (ES)

Leyendo archivos Excel con readxl

Instalamos readxl haciendo:

install.packages("readxl")

Función read_excel() para leer archivos Excel.

Otros paquetes del tidyverse

Otros paquetes del tidyverse

Herramientas para variables categóricas

Herramientas para variables categóricas

Herramientas para cadenas de caracteres

Herramientas para cadenas de caracteres

Programación funcional

Programación funcional